package session

import (
	"fmt"
	"github.com/pkg/errors"
	"strconv"
	"strings"
	"time"
)

// GetTableFromTableAndSplitFiled 根据表名和分表字段获取表名
// 如果分表字段为空，就返回原来的表名
// tableName 表名
// splitFiledVal 分表字段的值 一般只有两种类型 一个是int 一个是time.Time
func (s *Session) GetTableFromTableAndSplitFiled(tableName string, splitFiledVal interface{}) (string, error) {
	if splitFiledVal == nil {
		return tableName, errors.New("splitFiled is empty")
	}

	// 通过tableName 获取分表信息
	sname := tableName
	if strings.Contains(tableName, ".") {
		sname = strings.Split(tableName, ".")[1]
	}
	split, ok := (*s.spliter)[sname]
	if !ok {
		return tableName, nil
	}

	// 如果是取模的，包含数字这种 %1 %2 %3,取出%后面的内容，判断是否是数字，如果是数字，就取模
	if strings.Contains(split.TableShardType, "%") {
		splitType := strings.ReplaceAll(split.TableShardType, "%", "") // 取出%后面的内容
		// 判断是否是数字
		if splitTypeInt, err := strconv.Atoi(splitType); err == nil {
			if splitTypeInt == 1 {
				return tableName, nil
			}
			// splitFiledVal 转换成int
			splitFiledValInt, err := s.GetIntFromInterface(splitFiledVal)
			if err != nil {
				return tableName, errors.Wrap(err, "splitFiled is not int")
			}

			tableName = fmt.Sprintf("%s_%d", tableName, splitFiledValInt%splitTypeInt)
			return tableName, nil
		}

	}

	// splitType 不是数字，就是时间类型,取出时间类型的值 有 %m %d %w %h %y
	switch split.TableShardType {
	case "m":
		// 月份
		// splitFiledVal 转换成time.Time
		splitFiledValTime, err := s.GetTimeFromInterface(splitFiledVal)
		if err != nil {
			return tableName, errors.Wrap(err, "splitFiled is not time.Time")
		}
		tableName = fmt.Sprintf("%s_%d%02d", tableName, splitFiledValTime.Year(), splitFiledValTime.Month())
		return tableName, nil
	case "d":
		// 天
		// splitFiledVal 转换成time.Time
		splitFiledValTime, err := s.GetTimeFromInterface(splitFiledVal)
		if err != nil {
			return tableName, errors.Wrap(err, "splitFiled is not time.Time")
		}
		tableName = fmt.Sprintf("%s_%d%02d%02d", tableName, splitFiledValTime.Year(), splitFiledValTime.Month(), splitFiledValTime.Day())
		return tableName, nil

	case "w":
		// 周
		// splitFiledVal 转换成time.Time
		splitFiledValTime, err := s.GetTimeFromInterface(splitFiledVal)
		if err != nil {
			return tableName, errors.Wrap(err, "splitFiled is not time.Time")
		}
		// 获取这是这一年的第几周
		_, week := splitFiledValTime.ISOWeek()
		tableName = fmt.Sprintf("%s_%d%02d", tableName, splitFiledValTime.Year(), week)
		return tableName, nil
	case "h":
		// 小时
		// splitFiledVal 转换成time.Time
		splitFiledValTime, err := s.GetTimeFromInterface(splitFiledVal)
		if err != nil {
			return tableName, errors.Wrap(err, "splitFiled is not time.Time")
		}
		tableName = fmt.Sprintf("%s_%d%02d%02d%02d", tableName, splitFiledValTime.Year(), splitFiledValTime.Month(), splitFiledValTime.Day(), splitFiledValTime.Hour())
		return tableName, nil
	case "y":
		// 年
		// splitFiledVal 转换成time.Time
		splitFiledValTime, err := s.GetTimeFromInterface(splitFiledVal)
		if err != nil {
			return tableName, errors.Wrap(err, "splitFiled is not time.Time")
		}
		tableName = fmt.Sprintf("%s_%d", tableName, splitFiledValTime.Year())
		return tableName, nil

	}

	return tableName, errors.New("splitFiled is not int or time.Time")
}

// 仅支持获取以数字 分表的选手
func (s *Session) GetTableFromNone(tableName string) ([]string, error) {
	// 通过tableName 获取分表信息
	sname := tableName
	if strings.Contains(tableName, ".") {
		sname = strings.Split(tableName, ".")[1]
	}
	split, ok := (*s.spliter)[sname]
	if !ok {
		return []string{tableName}, nil
	}
	if strings.Contains(split.TableShardType, "%") {

		splitType := strings.ReplaceAll(split.TableShardType, "%", "") // 取出%后面的内容
		// 判断是否是数字
		if splitTypeInt, err := strconv.Atoi(splitType); err == nil {
			// 0-splitTypeInt-1,循环,生成表名tableName_0,tableName_1,tableName_2
			tableNames := make([]string, 0)
			for i := 0; i < splitTypeInt; i++ {
				tableNames = append(tableNames, fmt.Sprintf("%s_%d", tableName, i))
			}

			return tableNames, nil
		}
	}

	return []string{tableName}, errors.New("splitFiled is time.Time")
}

// 定义多个时间格式
var layouts = []string{
	"2006-01-02 15:04:05",
	"2006-01-02",
	"2006-01-02T15:04:05.999999999Z07:00",
	"2006-01-02 15:04:05.999999999 -0700 MST",
	"2006-01-02T15:04:05.999999999-07:00",
	"2006-01-02 15:04:05.999999999 -0700",
	"2006-01-02 15:04:05.999999999",
}

// 输入一个interface{}类型的值，返回一个time.Time 类型的值
func (s *Session) GetTimeFromInterface(val interface{}) (time.Time, error) {
	var (
		t   time.Time
		err error
	)
	if valStr, ok := val.(string); ok {
		for _, layout := range layouts {
			t, err = time.ParseInLocation(layout, valStr, time.Local)
			if err == nil {
				return t, nil
			}
		}
		// 返回转换结果或错误信息
		return time.Time{}, errors.Wrap(err, "val is not time.Time")
	}

	if valTime, ok := val.(time.Time); ok {
		if valTime.IsZero() {
			// 当时间是零值的时候，返回错误
			return time.Time{}, errors.New("val is zero time.Time(When the incoming parameter is a time, a zero value cannot be given)")
		}
		return valTime, nil
	}
	if valTime, ok := val.(*time.Time); ok {
		if valTime.IsZero() {
			return time.Time{}, errors.New("val is zero time.Time(When the incoming parameter is a time, a zero value cannot be given)")
		}
		return *valTime, nil
	}
	return time.Time{}, errors.New("val is not time.Time")
}

// 输入一个interface{}类型的值，返回一个int 类型的值
func (s *Session) GetIntFromInterface(val interface{}) (int, error) {
	// 判断是否是整数
	if valInt, ok := val.(int); ok {
		return valInt, nil
	}

	if valInt, ok := val.(*int); ok {
		return *valInt, nil
	}
	return 0, errors.New("val is not int")
}
